package com.xiaomaoguai.fcp.hsf.autoconfigure;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xiaomaoguai.fcp.hsf.utils.HttpClientUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.util.EntityUtils;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Random;

/**
 * @fileName: HsfInvocationHandler.java
 * @author: WeiHui
 * @date: 2018/7/14 15:59
 * @version: v1.0.0
 * @since JDK 1.8
 */
@Slf4j
@Data
public class HsfInvocationHandler implements InvocationHandler, Serializable {

	/**
	 * uid
	 */
	private static final long serialVersionUID = 5020345772562640082L;

	private static final String EQUALS = "equals";

	private static final String HASH_CODE = "hashCode";

	private static final String TO_STRING = "toString";

	private Class<?> serviceInterface;

	private String hsfServiceInterfaceName;

	private String serviceUrl;

	private String version;

	private boolean hsfClientMode;

	public HsfInvocationHandler(Class<?> serviceInterface, String hsfServiceInterfaceName, String serviceUrl, String version) {
		this.serviceInterface = serviceInterface;
		this.serviceUrl = serviceUrl;
		this.version = version;
		if (StringUtils.hasText(hsfServiceInterfaceName)) {
			this.hsfServiceInterfaceName = hsfServiceInterfaceName;
			this.hsfClientMode = true;
		}
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		String methodName = method.getName();
		Class<?>[] params = method.getParameterTypes();
		Type returnType = method.getGenericReturnType();

		// equals and hashCode are special cased
		if (EQUALS.equals(methodName) && params.length == 1 && params[0].equals(Object.class)) {
			Object value = args[0];
			if (value == null || !Proxy.isProxyClass(value.getClass())) {
				return Boolean.FALSE;
			}
			Object proxyHandler = Proxy.getInvocationHandler(value);
			if (!(proxyHandler instanceof HsfInvocationHandler)) {
				return Boolean.FALSE;
			}
			HsfInvocationHandler handler = (HsfInvocationHandler) proxyHandler;
			return handler.getServiceInterface() == serviceInterface && serviceUrl.equals(handler.getServiceUrl());
		} else if (HASH_CODE.equals(methodName) && params.length == 0) {
			return serviceUrl.hashCode();
		} else if (TO_STRING.equals(methodName) && params.length == 0) {
			return "HsfInvocationHandler[ serviceUrl:" + serviceUrl + " ,  version:" + version + "]";
		}

		int len = args == null ? 0 : args.length;
		Object[] argsName = new Object[len];
		Object[] argsValue = new Object[len];
		Class<?>[] parameterTypes = method.getParameterTypes();
		for (int i = 0; i < len; i++) {
			argsName[i] = parameterTypes[i].getName();
			//对于String 类型的入参需要特殊处理
			if (parameterTypes[i].equals(String.class)) {
				if (args[i] == null) {
					argsValue[i] = null;
				} else {
					argsValue[i] = JSONObject.toJSONString(args[i]);
				}
			} else {
				argsValue[i] = args[i];
			}
		}
		String url = getUrl(methodName);
		log.info("invoke url : {} , param:{}", url, JSON.toJSONString(args));
		String[] hsfArgs = new String[]{JSON.toJSONString(argsName), JSON.toJSONString(argsValue)};
		ByteArrayEntity byteArrayEntity = new ByteArrayEntity(JSON.toJSONBytes(hsfArgs));
		HttpPost httpPost = new HttpPost(url);
		httpPost.setEntity(byteArrayEntity);
		CloseableHttpResponse response = HttpClientUtils.getHttpClient().execute(httpPost);
		String string = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
		return JSONObject.parseObject(string, returnType);
	}

	/**
	 * 获取当事人的HSF服务URL
	 *
	 * @param callMethodName 调用方法
	 * @return 调用URL
	 */
	private String getUrl(String callMethodName) {
		StringBuilder builder = new StringBuilder();
		builder.append(getSlbUrl());
		if (hsfClientMode) {
			builder.append(this.hsfServiceInterfaceName);
		} else {
			builder.append(serviceInterface.getName());
		}
		builder.append(":");
		builder.append(version);
		builder.append("/");
		builder.append(callMethodName);
		return builder.toString();
	}

	/**
	 * 根据配置的地址随机选取一个url
	 *
	 * @return 随机url
	 */
	private String getSlbUrl() {
		String[] urls = serviceUrl.split(",");
		Random random = new SecureRandom();
		int index = random.nextInt(urls.length);
		return urls[index];
	}

}
